class StatPrinter extends TreeParser;

options {
	importVocab = Java;
}

{
    public void setLines(LinkedList lines) {
        _lines = lines;
    }

    public void setIdent(int value) {
        _ident = value;
    }
    
    public void setAddColon(boolean value) {
        _addColon = value;
    }
    
    public void setFGNode(FlowGraphNode node) {
        _fgnode = node;
    }

    private LinkedList _lines;

    private StringBuffer _currentModifiers;
    private StringBuffer _currentID;
    private int _ntypeArray;
    private String _typeName;    
    private String _varInitializer = null;
    private StringBuffer _currentEXPR;
    private String _currentConst;
    private StringBuffer _arrayIndexing;
    private StringBuffer _currentPar;
    private StringBuffer _currentArrayDecl;
    private StringBuffer _initializer;
    
    private LinkedList _exprList = new LinkedList();
    private Stack _exprStack = new Stack();

    private static final int _IDENT_INC = 4;
    private int _ident;

    private boolean _addColon = true;
    private FlowGraphNode _fgnode;
}

statement: stat 

	|   #(n1:CTOR_CALL { StringBuffer ret = new StringBuffer("this("); }
	       elist {
	          if(_exprList.size() > 0) {
	               for(int i = 0;i < _exprList.size() - 1;i++) {
		           ret.append((String) _exprList.get(i) + ",");
		       }
		       ret.append((String) _exprList.get(_exprList.size() - 1));
	           }
	           ret.append(")");
	           _currentEXPR = new StringBuffer(ret.toString());

		   Line l;
		   if(_addColon) {
	               l = new Line(_currentEXPR.toString() + ";", 
		           n1, _fgnode, 1, _ident, _lines.size());
		   }
		   else {
		       l = new Line(_currentEXPR.toString(), n1, 
		           _fgnode, 1, _ident, _lines.size());
		   }
		   _lines.add(l);
		   ((MethodCallNode) _fgnode).setLine(l);

	           _exprList = (LinkedList) _exprStack.pop();
               })
	
	|   #(n2:METHOD_CALL { StringBuffer ret = new StringBuffer(); }
	             primaryExpression { ret.append(_currentEXPR.toString() + "("); }
		     elist {
		         if(_exprList.size() > 0) {
		             for(int i = 0;i < _exprList.size() - 1;i++) {
			         ret.append((String) _exprList.get(i) + ",");
			     }
			     ret.append((String) _exprList.get(_exprList.size() - 1));
			 }
			 ret.append(")");
			 _currentEXPR = new StringBuffer(ret.toString());
			 
			 Line l;
		         if(_addColon) {
	                     l = new Line(_currentEXPR.toString() + ";", n2, 
			         _fgnode, 1, _ident, _lines.size());
		         }
		         else {
		            l = new Line(_currentEXPR.toString(), n2, 
			        _fgnode, 1, _ident, _lines.size());
		         }
		         _lines.add(l); 
			 ((MethodCallNode)_fgnode).setLine(l);
			 
			 _exprList = (LinkedList) _exprStack.pop();
		     } )
		      
	|  #(n3:SUPER_CTOR_CALL { StringBuffer ret = new StringBuffer("super("); }
	        ( elist {
	              if(_exprList.size() > 0) {
	                  for(int i = 0;i < _exprList.size() - 1;i++) {
		              ret.append((String) _exprList.get(i) + ",");
		           }
		           ret.append((String) _exprList.get(_exprList.size() - 1));
	               }
	               ret.append(")");
	               _currentEXPR = new StringBuffer(ret.toString());

		       Line l;
		       if(_addColon) {
	                   l = new Line(_currentEXPR.toString() + ";", 
			       n1, _fgnode, 1, _ident, _lines.size());
		       }
		       else {
		           l = new Line(_currentEXPR.toString(), n1, 
			       _fgnode, 1, _ident, _lines.size());
		       }
		       _lines.add(l); 
		       ((MethodCallNode)_fgnode).setLine(l);
		       
	               _exprList = (LinkedList) _exprStack.pop(); } 

	          | primaryExpression { System.out.println("STAT PRINTER!!!");} elist )
	      )
	;

stat:	        // typeDefinition  { System.out.println("Classe local!!!!"); }

		variableDef

	|	n1:expression {
	            Line l;
		    if(_addColon) {
	                l = new Line(_currentEXPR.toString() + ";", n1, 
			    _fgnode, 1, _ident, _lines.size());
		    }
		    else {
		        l = new Line(_currentEXPR.toString(), n1, 
			    _fgnode, 1, _ident, _lines.size());
		    }
		    _lines.add(l);
		    // Eu associo a linha gerada com o BB no codigo FlowGraph._codeGen()
		    if(_fgnode != null && _fgnode.getType() == FlowGraphNode.METHOD_CALL) {
		        ((MethodCallNode)_fgnode).setLine(l);
		    }
		}

	|	EMPTY_STAT 
	;

typeSpec        { _ntypeArray = 0; }
	:	#(TYPE typeSpecArray)
	;

typeSpecArray   
	:	#( ARRAY_DECLARATOR { _ntypeArray++; } typeSpecArray )
	|	type
	;

type:	identifier 		{ _typeName = _currentID.toString(); }
	|	n1:builtInType	{ _typeName = n1.getText(); }
	;

builtInType
    :   "void"
    |   "boolean"
    |   "byte"
    |   "char"
    |   "short"
    |   "int"
    |   "float"
    |   "long"
    |   "double"
    ;

modifiers   { _currentModifiers = new StringBuffer(); }
	:	#( MODIFIERS (n1:modifier { _currentModifiers.append(n1.getText() + " "); } )* )    
	;

modifier
    :   "private"
    |   "public"
    |   "protected"
    |   "static"
    |   "transient"
    |   "final"
    |   "abstract"
    |   "native"
    |   "threadsafe"
    |   "synchronized"
    |   "const"
    |   "volatile"
	|	"strictfp"
    ;
    
variableDef    	{ StringBuffer line = new StringBuffer(); }
	:	#(n1:VARIABLE_DEF modifiers { line.append(_currentModifiers.toString()); }
				  typeSpec  {
				      line.append(_typeName + " ");
				      for(int i = 0;i < _ntypeArray;i++) {
				          line.append("[]");
				      }
				      line.append(" ");
				  }

				  variableDeclarator {
				      line.append(_currentID.toString() + " ");
				  }			

				  varInitializer {
				      if(_varInitializer != null) {
				          line.append(_varInitializer);
				          _varInitializer = null;
				      }
				  }

				  { 
				    if(_addColon) { 
				       line.append(";"); 
				    }
				    Line l = new Line(line.toString(), n1, _fgnode, 
				        1, _ident, _lines.size()); 
				    _lines.add(l); 

				    // No caso do fgnode ser um BB, o codigo do FlowGraph._codeGen resolve/
				    // a parada...
				    if(_fgnode != null && 
				       _fgnode.getType() == FlowGraphNode.METHOD_CALL) {
				        ((MethodCallNode)_fgnode).setLine(l);
				    }

				  } )
	;

objectinitializer
	:	#(INSTANCE_INIT slist)
	;

variableDeclarator 				{ _currentID = new StringBuffer(); }
	:	n1:IDENT 			{ _currentID.append(n1.getText()); }
	|	LBRACK variableDeclarator  	{ System.out.println("UMA SITUACAO NAO PROCESSADA : LBRACK variableDeclarator"); }
	;

varInitializer { _initializer = new StringBuffer(); }
	:	#(ASSIGN initializer) { _varInitializer = new String("= " + _initializer.toString()); }
	|
	;

initializer    { _currentEXPR = new StringBuffer(); }
	:	expression { _initializer.append(_currentEXPR.toString()); }
	|	arrayInitializer
	;

arrayInitializer
	:	#(ARRAY_INIT { _initializer.append("{"); } 
	           initializer ( {_initializer.append(","); } initializer)* { _initializer.append("}"); }
		  )
	;

identifier    { _currentID = new StringBuffer(); } 
	:	x:IDENT  		    { _currentID.append(x.getText()); }
	|	#( DOT identifier y:IDENT ) { _currentID.append("." + y.getText()); }
	;

slist
	:	#( SLIST (stat)* )
	;

tryBlock
	:	#( "try" slist (handler)* (#("finally" slist))? )
	;

handler
	:	#( "catch" parameterDef slist )

	;

parameterDef    { _currentPar = new StringBuffer(); }
	:	#(PARAMETER_DEF 
	            modifiers { _currentPar.append(_currentModifiers.toString()); }
	            typeSpec {
		        _currentPar.append(_typeName + " ");
		        for(int i = 0;i < _ntypeArray;i++) {
			    _currentPar.append("[]");
			}
			_currentPar.append(" ");
		    }
		    n1:IDENT { _currentPar.append(n1.getText()); } )
	;

elist      { _exprStack.push(_exprList); _exprList = new LinkedList(); }
	:	#( ELIST (expression { _exprList.add(_currentEXPR.toString()); } )* )
	;

expression
	:	#(EXPR expr)
	;

expr: 
	        #(QUESTION expr { String _exp1 = _currentEXPR.toString(); }  
		           expr { String _exp2 = _currentEXPR.toString(); } 
			   expr { String _exp3 = _currentEXPR.toString(); 
			       _currentEXPR = new StringBuffer("(" + _exp1 + ")?" + _exp2 + ":" + _exp3); 
			   } )

	|	#(ASSIGN expr { String _exp1 = _currentEXPR.toString(); } 
	                 expr { String _exp2 = _currentEXPR.toString();
                               _currentEXPR = new StringBuffer(_exp1 + " = " + _exp2);
			 } )

	|	#(PLUS_ASSIGN expr { String _exp1 = _currentEXPR.toString(); }
			      expr { String _exp2 = _currentEXPR.toString(); 
			          _currentEXPR = new StringBuffer(_exp1 + " += " + _exp2);
			      } )

	|	#(MINUS_ASSIGN expr { String _exp1 = _currentEXPR.toString(); }
			       expr { String _exp2 = _currentEXPR.toString();
			          _currentEXPR = new StringBuffer(_exp1 + " -= " + _exp2);
		 	       } )

	|	#(STAR_ASSIGN expr { String _exp1 = _currentEXPR.toString(); }
			      expr { String _exp2 = _currentEXPR.toString(); 
			          _currentEXPR = new StringBuffer(_exp1 + " *= " + _exp2);
			      } )

	|	#(DIV_ASSIGN expr { String _exp1 = _currentEXPR.toString(); }
			     expr { String _exp2 = _currentEXPR.toString(); 
			          _currentEXPR = new StringBuffer(_exp1 + " /= " + _exp2);
			     } )

	|	#(MOD_ASSIGN  expr { String _exp1 = _currentEXPR.toString(); }
			      expr { String _exp2 = _currentEXPR.toString();
			          _currentEXPR = new StringBuffer(_exp1 + " %= " + _exp2);
			      } )

	|	#(SR_ASSIGN expr { String _exp1 = _currentEXPR.toString(); }
			    expr { String _exp2 = _currentEXPR.toString();
			          _currentEXPR = new StringBuffer(_exp1 + " >>= " + _exp2);
			    } )

	|	#(BSR_ASSIGN  expr { String _exp1 = _currentEXPR.toString(); }
			      expr { String _exp2 = _currentEXPR.toString(); 
			          _currentEXPR = new StringBuffer(_exp1 + " >>>= " + _exp2);
			      } )

	|	#(SL_ASSIGN   expr { String _exp1 = _currentEXPR.toString(); }
			      expr { String _exp2 = _currentEXPR.toString(); 
			          _currentEXPR = new StringBuffer(_exp1 + " <<= " + _exp2);
			      } )

	|	#(BAND_ASSIGN expr { String _exp1 = _currentEXPR.toString(); }
			      expr { String _exp2 = _currentEXPR.toString(); 
			          _currentEXPR = new StringBuffer(_exp1 + " &= " + _exp2);
			      } )

	|	#(BXOR_ASSIGN expr { String _exp1 = _currentEXPR.toString(); }
			      expr { String _exp2 = _currentEXPR.toString(); 
			          _currentEXPR = new StringBuffer(_exp1 + " ^= " + _exp2);
			      } )

	|	#(BOR_ASSIGN  expr { String _exp1 = _currentEXPR.toString(); }
			      expr { String _exp2 = _currentEXPR.toString(); 
			          _currentEXPR = new StringBuffer(_exp1 + " |= " + _exp2);
			      } )

	|	#(LOR expr { String _exp1 = _currentEXPR.toString(); }
			      expr { String _exp2 = _currentEXPR.toString(); 
			          _currentEXPR = new StringBuffer("(" + _exp1 + " || " + _exp2 + ")");
			      } )

	|	#(LAND expr { String _exp1 = _currentEXPR.toString(); }
			      expr { String _exp2 = _currentEXPR.toString(); 
			          _currentEXPR = new StringBuffer("(" + _exp1 + " && " + _exp2 + ")");
			      } )

	|	#(BOR expr { String _exp1 = _currentEXPR.toString(); }
			      expr { String _exp2 = _currentEXPR.toString(); 
			          _currentEXPR = new StringBuffer("(" + _exp1 + " | " + _exp2 + ")");
			      } )

	|	#(BXOR expr { String _exp1 = _currentEXPR.toString(); }
			      expr { String _exp2 = _currentEXPR.toString(); 
			          _currentEXPR = new StringBuffer("(" + _exp1 + " ^ " + _exp2 + ")");
			      } )

	|	#(BAND expr { String _exp1 = _currentEXPR.toString(); }
			      expr { String _exp2 = _currentEXPR.toString(); 
			          _currentEXPR = new StringBuffer("(" + _exp1 + " & " + _exp2 + ")");
			      } )

	|	#(NOT_EQUAL expr { String _exp1 = _currentEXPR.toString(); }
			      expr { String _exp2 = _currentEXPR.toString(); 
			          _currentEXPR = new StringBuffer("(" + _exp1 + " != " + _exp2 + ")");
			      } )

	|	#(EQUAL expr { String _exp1 = _currentEXPR.toString(); }
			      expr { String _exp2 = _currentEXPR.toString(); 
			          _currentEXPR = new StringBuffer("(" + _exp1 + " == " + _exp2 + ")");
			      } )

	|	#(LT expr { String _exp1 = _currentEXPR.toString(); }
			      expr { String _exp2 = _currentEXPR.toString(); 
			          _currentEXPR = new StringBuffer("(" + _exp1 + " < " + _exp2 + ")");
			      } )

	|	#(GT expr { String _exp1 = _currentEXPR.toString(); }
			      expr { String _exp2 = _currentEXPR.toString(); 
			          _currentEXPR = new StringBuffer("(" + _exp1 + " > " + _exp2 + ")");
			      } )

	|	#(LE expr { String _exp1 = _currentEXPR.toString(); }
			      expr { String _exp2 = _currentEXPR.toString(); 
			          _currentEXPR = new StringBuffer("(" + _exp1 + " <= " + _exp2 + ")");
			      } )

	|	#(GE expr { String _exp1 = _currentEXPR.toString(); }
			      expr { String _exp2 = _currentEXPR.toString(); 
			          _currentEXPR = new StringBuffer("(" + _exp1 + " >= " + _exp2 + ")");
			      } )

	|	#(SL expr { String _exp1 = _currentEXPR.toString(); }
			      expr { String _exp2 = _currentEXPR.toString(); 
			          _currentEXPR = new StringBuffer("(" + _exp1 + " << " + _exp2 + ")");
			      } )

	|	#(SR expr { String _exp1 = _currentEXPR.toString(); }
			      expr { String _exp2 = _currentEXPR.toString(); 
			          _currentEXPR = new StringBuffer("(" + _exp1 + " >> " + _exp2 + ")");
			      } )

	|	#(BSR expr { String _exp1 = _currentEXPR.toString(); }
			      expr { String _exp2 = _currentEXPR.toString(); 
			          _currentEXPR = new StringBuffer("(" + _exp1 + " >>> " + _exp2 + ")");
			      } )

	|	#(PLUS expr { String _exp1 = _currentEXPR.toString(); }
			      expr { String _exp2 = _currentEXPR.toString(); 
			          _currentEXPR = new StringBuffer("(" + _exp1 + " + " + _exp2 + ")");
			      } )

	|	#(MINUS expr { String _exp1 = _currentEXPR.toString(); }
			      expr { String _exp2 = _currentEXPR.toString(); 
			          _currentEXPR = new StringBuffer("(" + _exp1 + " - " + _exp2 + ")");
			      } )

	|	#(DIV expr { String _exp1 = _currentEXPR.toString(); }
			      expr { String _exp2 = _currentEXPR.toString(); 
			          _currentEXPR = new StringBuffer("(" + _exp1 + " / " + _exp2 + ")");
			      } )

	|	#(MOD expr { String _exp1 = _currentEXPR.toString(); }
			      expr { String _exp2 = _currentEXPR.toString(); 
			          _currentEXPR = new StringBuffer("(" + _exp1 + " % " + _exp2 + ")");
			      } )

	|	#(STAR expr { String _exp1 = _currentEXPR.toString(); }
		       expr { String _exp2 = _currentEXPR.toString(); 
			          _currentEXPR = new StringBuffer("(" + _exp1 + " * " + _exp2 + ")");
			      } )
	
	|	#(INC expr { String _exp1 = _currentEXPR.toString(); 
	                     _currentEXPR = new StringBuffer("++" + _exp1); 
			   })

	|	#(DEC expr { String _exp1 = _currentEXPR.toString(); 
	                     _currentEXPR = new StringBuffer("--" + _exp1); } )

	|	#(POST_INC expr { String _exp1 = _currentEXPR.toString(); 
	                          _currentEXPR = new StringBuffer(_exp1 + "++"); } )

	|	#(POST_DEC expr { String _exp1 = _currentEXPR.toString(); 
	                          _currentEXPR = new StringBuffer(_exp1 + "--"); } )

	|	#(BNOT expr { String _exp1 = _currentEXPR.toString(); 
	                      _currentEXPR = new StringBuffer("(~" + _exp1 + ")"); } )

	|	#(LNOT expr { String _exp1 = _currentEXPR.toString(); 
	                      _currentEXPR = new StringBuffer("(!" + _exp1 + ")"); } )

	|	#("instanceof" expr { String _exp1 = _currentEXPR.toString(); }
			       expr { String _exp2 = _currentEXPR.toString(); 
			          _currentEXPR = new StringBuffer("(" + _exp1 + " instanceof " + _exp2 + ")");


			       } )

	|	#(UNARY_MINUS expr { String _exp1 = _currentEXPR.toString(); 
	                             _currentEXPR = new StringBuffer("-" + _exp1); } )

	|	#(UNARY_PLUS expr { String _exp1 = _currentEXPR.toString(); 
	                            _currentEXPR = new StringBuffer("+" + _exp1); } )

	|	primaryExpression

	;

primaryExpression
    :   n1:IDENT { _currentEXPR = new StringBuffer(n1.getText()); }

    |   #(	DOT { String dot; }
			(	expr  { dot = _currentEXPR.toString(); }

				(	n2:IDENT { _currentEXPR = new StringBuffer(dot + "." + n2.getText()); }

				|	arrayIndex  { System.out.println("primaryExpr arrayIndex!!!"); }

				|	"this"  { _currentEXPR = new StringBuffer(dot + ".this"); }

				|	"class"  { 
				            _currentEXPR = new StringBuffer(dot + ".class");
				        }

				|	#( "new" IDENT elist ) {  System.out.println("primaryExpr newIDENT!!!"); }

				|   "super"  { System.out.println("primaryExpr super"); }

				)
			|	#(ARRAY_DECLARATOR typeSpecArray)  { System.out.println("primaryExpr arraydecla!!"); }
			
			|	builtInType ("class")? { System.out.println("primaryExpr builtIntype!!!"); }
			
			)
		)

	|	arrayIndex

	|	#(METHOD_CALL { StringBuffer ret = new StringBuffer(); }
	             primaryExpression { ret.append(_currentEXPR.toString() + "("); }
		     elist {
		         if(_exprList.size() > 0) {
		             for(int i = 0;i < _exprList.size() - 1;i++) {
			         ret.append((String) _exprList.get(i) + ",");
			     }
			     ret.append((String) _exprList.get(_exprList.size() - 1));
			 }
			 ret.append(")");
			 _currentEXPR = new StringBuffer(ret.toString());
			 
			 _exprList = (LinkedList) _exprStack.pop();
		     } )

	|	#(TYPECAST { StringBuffer ret = new StringBuffer("(("); }
	             typeSpec {
		         ret.append(_typeName + " ");
		         for(int i = 0;i < _ntypeArray;i++) {
		             ret.append("[]");
		         }
			 ret.append(")");
		     }
		     expr { 
		         ret.append(_currentEXPR.toString() + ")"); 
		         _currentEXPR = new StringBuffer(ret.toString()); 
	             } )

	|   newExpression 

	|   constant 	{ _currentEXPR = new StringBuffer(_currentConst); }
        |   "super" 	{ _currentEXPR = new StringBuffer("super"); }
        |   "true" 	{ _currentEXPR = new StringBuffer("true"); }
        |   "false" 	{ _currentEXPR = new StringBuffer("false"); }
        |   "this" 	{ _currentEXPR = new StringBuffer("this"); }
        |   "null" 	{ _currentEXPR = new StringBuffer("null"); }

        |	// type name used with instanceof
		typeSpec { _currentEXPR = new StringBuffer(_typeName); }
	;

ctorCall
	:	#( CTOR_CALL elist )
	|	#( SUPER_CTOR_CALL
			(	elist
			|	primaryExpression elist
			)
		 )
	;

arrayIndex
	:	#(INDEX_OP { StringBuffer _arrayIndexing = new StringBuffer(); }
	              primaryExpression {
		          _arrayIndexing.append(_currentEXPR.toString());
		      }					  
		      expression { _arrayIndexing.append("[" + _currentEXPR.toString() + "]"); 			
				   _currentEXPR = _arrayIndexing;
		      } )
	;

constant
    :   n1:NUM_INT 		{ _currentConst = n1.getText(); }
    |   n2:CHAR_LITERAL	        { _currentConst = n2.getText(); }
    |   n3:STRING_LITERAL	{ _currentConst = n3.getText(); }
    |   n4:NUM_FLOAT		{ _currentConst = n4.getText(); }
    |   n5:NUM_DOUBLE		{ _currentConst = n5.getText(); }
    |   n6:NUM_LONG		{ _currentConst = n6.getText(); }
    ;

newExpression   { StringBuffer ret = new StringBuffer("new "); }
	:	#(	"new" type { ret.append(_typeName); }
	
			(	{ _currentArrayDecl = new StringBuffer(); } 
			        newArrayDeclarator {
				    ret.append(_currentArrayDecl.toString());
			        }

				(arrayInitializer {
				    ret.append("= " + _initializer.toString());
				})?				
				{ _currentEXPR = new StringBuffer(ret.toString()); }
			
			|	elist  {
                                    ret.append("(");
				    if(_exprList.size() > 0) {
 		                       for(int i = 0;i < _exprList.size() - 1;i++) {
			                   ret.append((String) _exprList.get(i) + ",");
			                }
			                ret.append((String) _exprList.get(_exprList.size() - 1));
			            }
			            ret.append(")");
			            _currentEXPR = new StringBuffer(ret.toString());

                                    _exprList = (LinkedList) _exprStack.pop();
			        }
				//(objBlock { 
				//    System.out.println("Nao era para processar o objblock!"); })?
			)
		)
	;

newArrayDeclarator  { boolean hasEXPR = false; }
	:	#( ARRAY_DECLARATOR 

		       (newArrayDeclarator)? 

		       (expression {		       
			    _currentArrayDecl.append("[" + _currentEXPR.toString() + "]");
                            hasEXPR = true;
		        } )? 
		       
		        {
		            if(!hasEXPR) {
			       _currentArrayDecl.append("[]");			   
			    }
		        }
		 )
	;
